#ifndef __FAT32_H__
#define __FAT32_H__
#include "libs/types.h"
#include "kernel/vfs/vfs.h"

#define	ATTR_READ_ONLY	(1 << 0)
#define ATTR_HIDDEN	(1 << 1)
#define ATTR_SYSTEM	(1 << 2)
#define ATTR_VOLUME_ID	(1 << 3)
#define ATTR_DIRECTORY	(1 << 4)
#define ATTR_ARCHIVE	(1 << 5)
#define ATTR_LONG_NAME	(ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID)


struct FAT32_BootSector
{
	unsigned char BS_jmpBoot[3];
	unsigned char BS_OEMName[8];
	unsigned short BPB_BytesPerSec;
	unsigned char BPB_SecPerClus;
	unsigned short BPB_RsvdSecCnt;
	unsigned char BPB_NumFATs;
	unsigned short BPB_RootEntCnt;
	unsigned short BPB_TotSec16;
	unsigned char BPB_Media;
	unsigned short BPB_FATSz16;
	unsigned short BPB_SecPerTrk;
	unsigned short BPB_NumHeads;
	unsigned int BPB_HiddSec;
	unsigned int BPB_TotSec32;
	
	unsigned int BPB_FATSz32;
	unsigned short BPB_ExtFlags;
	unsigned short BPB_FSVer;
	unsigned int BPB_RootClus;
	unsigned short BPB_FSInfo;
	unsigned short BPB_BkBootSec;
	unsigned char BPB_Reserved[12];

	unsigned char BS_DrvNum;
	unsigned char BS_Reserved1;
	unsigned char BS_BootSig;
	unsigned int BS_VolID;
	unsigned char BS_VolLab[11];
	unsigned char BS_FilSysType[8];

	unsigned char BootCode[420];

	unsigned short BS_TrailSig;
}__attribute__((packed));


struct FAT32_FSInfo
{
	unsigned int FSI_LeadSig;
	unsigned char FSI_Reserved1[480];
	unsigned int FSI_StrucSig;
	unsigned int FSI_Free_Count;
	unsigned int FSI_Nxt_Free;
	unsigned char FSI_Reserved2[12];
	unsigned int FSI_TrailSig;
}__attribute__((packed));







struct FAT32_Directory
{
	unsigned char DIR_Name[11];
	unsigned char DIR_Attr;
	unsigned char DIR_NTRes;	//EXT|BASE => 8(BASE).3(EXT)
					//BASE:LowerCase(8),UpperCase(0)
					//EXT:LowerCase(16),UpperCase(0)
	unsigned char DIR_CrtTimeTenth;
	unsigned short DIR_CrtTime;	
	unsigned short DIR_CrtDate;
	unsigned short DIR_LastAccDate;
	unsigned short DIR_FstClusHI;
	unsigned short DIR_WrtTime;
	unsigned short DIR_WrtDate;
	unsigned short DIR_FstClusLO;
	unsigned int DIR_FileSize;
}__attribute__((packed));

#define LOWERCASE_BASE (8)
#define LOWERCASE_EXT (16)

struct FAT32_LongDirectory
{
	unsigned char LDIR_Ord;
	unsigned short LDIR_Name1[5];
	unsigned char LDIR_Attr;
	unsigned char LDIR_Type;
	unsigned char LDIR_Chksum;
	unsigned short LDIR_Name2[6];
	unsigned short LDIR_FstClusLO;
	unsigned short LDIR_Name3[2];
}__attribute__((packed));





/////////////FAT32 for VFS

struct FAT32_sb_info
{
	unsigned long start_sector;
	unsigned long sector_count;

	long sector_per_cluster;
	long bytes_per_cluster;
	long bytes_per_sector;

	unsigned long Data_firstsector;
	unsigned long FAT1_firstsector;
	unsigned long sector_per_FAT;
	unsigned long NumFATs;

	unsigned long fsinfo_sector_infat;
	unsigned long bootsector_bk_infat;
	
	struct FAT32_FSInfo * fat_fsinfo;
};


class FAT32DirEntry : public DirEntry
{
private:
    /* data */
public:

    
    FAT32DirEntry(/* args */);
    ~FAT32DirEntry();

//    virtual  int64_t compare(DirEntry* parentDentry,char* sourceFilename,char* destinationFilename);
//    virtual int64_t hash(DirEntry* dentry,char* filename);
//    virtual int64_t release(DirEntry* dentry);
//    virtual int64_t iput(DirEntry* dentry,IndexNode* inode);
};


struct FAT32_inode_info
{
	unsigned long first_cluster;
	unsigned long dentry_location;	////dentry struct in cluster(0 is root,1 is invalid)
	unsigned long dentry_position;	////dentry struct offset in cluster

	unsigned short create_date;
	unsigned short create_time;

	unsigned short write_date;
	unsigned short write_time;
};


class FAT32SuperBlock : public SuperBlock
{
private:
    /* data */
public:

    FAT32SuperBlock(/* args */);
    ~FAT32SuperBlock();
};




class FAT32IndexNode : public IndexNode
{
private:
    /* data */
public:

    FAT32IndexNode(/* args */);
    ~FAT32IndexNode();
	virtual DirEntry* FAT32IndexNode::create(DirEntry* dentry,char* name,uint64_t attribute);
	virtual DirEntry* lookup(IndexNode * parent_inode,DirEntry * dest_dentry);
	// virtual long mkdir(IndexNode * inode,DirEntry * dentry,int32_t mode);
	// virtual long rmdir(IndexNode * inode,DirEntry * dentry);
	// virtual long rename(IndexNode * old_inode,DirEntry * old_dentry,IndexNode * new_inode,DirEntry * new_dentry);
	// virtual long getattr(DirEntry * dentry,unsigned long * attr);
	// virtual long setattr(DirEntry * dentry,unsigned long * attr);

};


class FAT32File : public File
{
private:
    /* data */
public:

    FAT32File(/* args */);
    ~FAT32File();

   virtual int64_t open(IndexNode* inode,File* filp);
   virtual int64_t close(IndexNode* inode,File* filp);
   virtual int64_t read(char* buf, uint64_t count,int64_t* position);
   virtual int64_t write(char* buf, uint64_t count,int64_t* position);
   virtual int64_t lseek(int64_t offset, int64_t origin);
//    virtual int64_t ioctl(IndexNode* inode,File* filp,uint64_t cmd,uint64_t arg);
};














class Fat32FS : public FileSystem
{
private:
    /* data */
public:
	static Fat32FS* fat32m;
    SuperBlock* rootSb;
    Fat32FS(/* args */);
    ~Fat32FS();
	DirEntry* pathSearch(char* name,uint64_t flags);
	void createFile(char* path,uint64_t attribute,uint64_t type);
	void createDirectory();
	
	static uint32_t readFATEntry(FAT32_sb_info*,uint32_t fatEntry);
	static uint64_t writeFATEntry(FAT32_sb_info* fsbi,uint32_t fatEntry,uint32_t value);
	static uint64_t findAvailableCluster(FAT32_sb_info* fsbi);
	virtual SuperBlock* readSuperBlock(void* buf);

};	



#define FAT32FILESYSTEM \
Fat32FS::fat32m

#endif